💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    책 목록 웹앱 만들기2 답안 | ✅저자: 이유정(박사)

    🔹 간단한 책 제목과 저자를 저장하고, 화면에 예쁘게 출력하는 웹앱

    bookproject/
    ├── manage.py
    ├── bookproject/
    │   └── settings.py, urls.py ...
    └── books/
        ├── models.py
        ├── views.py
        ├── urls.py
        ├── templates/
        │   └── books/
        │       ├── base.html
        │       ├── book_list.html
        │       ├── book_detail.html
        │       └── book_results.html
        └── static/
            └── books/
                └── css/
                    └── style.css
    

    모델 정의 – books/models.py

    from django.db import models
    
    class Book(models.Model):
        title = models.CharField(max_length=200)
        author = models.CharField(max_length=100)
        votes = models.IntegerField(default=0)  # 투표 수 추가
    
        def __str__(self):
            return f"{self.title} by {self.author}"
    

    모델 정의 books/models.py 파일에서 다음을 수행하세요.

    • 책 정보를 저장할 Book 모델을 정의합니다.
    • 다음 필드를 포함하세요:
      • title: 책 제목, 최대 200자
      • author: 저자 이름, 최대 100자
      • votes: 정수, 기본값은 0, 사용자 투표 수 저장
    id (자동 생성) title author votes
    1 데미안 헤르만 헤세 2
    2 어린 왕자 앙투안 드 생텍쥐페리 5
    3 삼국지 나관중 4

    뷰 작성 – books/views.py

    from django.shortcuts import render, get_object_or_404
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    from django.views import generic
    from .models import Book
    from django.db.models import F
    
    # 책 목록 보기 (ListView)
    class BookListView(generic.ListView):
        model = Book
        template_name = "books/book_list.html"
        context_object_name = "books"
    
    # 책 상세 및 투표 폼 (DetailView)
    class BookDetailView(generic.DetailView):
        model = Book
        template_name = "books/book_detail.html"
        context_object_name = "book"
    
    # 투표 처리 함수형 뷰
    def vote(request, pk):
        book = get_object_or_404(Book, pk=pk)
        if request.method == "POST":
            book.votes = F("votes") + 1  # 안전한 증가
            book.save()
            return HttpResponseRedirect(reverse("books:results", args=(book.id,)))
        return render(request, "books/book_detail.html", {
            "book": book,
            "error_message": "Invalid access.",
        })
    
    # 결과 보기 (DetailView 재사용)
    class BookResultsView(generic.DetailView):
        model = Book
        template_name = "books/book_results.html"
        context_object_name = "book"
    

    ✔️ 의사코드:

    함수 book_list(요청):
        - Book 모델에서 모든 책 데이터를 가져온다 → books 변수에 저장
        - 'books/book_list.html' 템플릿을 사용하여 웹 페이지를 만든다
        - 템플릿에 books 데이터를 함께 전달한다
        - 생성된 웹 페이지를 사용자에게 응답으로 보낸다
    

    앱 URL 설정 – books/urls.py

    from django.urls import path
    from . import views
    
    app_name = "books"
    
    urlpatterns = [
        path("", views.BookListView.as_view(), name="book_list"),
        path("<int:pk>/", views.BookDetailView.as_view(), name="book_detail"),
        path("<int:pk>/vote/", views.vote, name="vote"),
        path("<int:pk>/results/", views.BookResultsView.as_view(), name="results"),
    ]
    

    프로젝트 URL 연결 – bookproject/urls.py

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path("admin/", admin.site.urls),
        path("books/", include("books.urls")),
    ]
    

    템플릿 – books/templates/books/base.html

    <!DOCTYPE html>
    <html lang="ko">
    <head>
        <meta charset="UTF-8">
        <title>{% block title %}Book List{% endblock %}</title>
        <link rel="stylesheet" href="{% static 'books/css/style.css' %}">
    </head>
    <body>
        <div class="container">
            {% block content %}{% endblock %}
        </div>
    </body>
    </html>
    

    템플릿 – books/templates/books/book_list.html

    {% extends "books/base.html" %}
    
    {% block title %}책 목록{% endblock %}
    
    {% block content %}
    <h1>책 목록</h1>
    <ul class="book-list">
        {% for book in books %}
        <li>
            <a href="{% url 'books:book_detail' book.id %}">{{ book.title }}</a> by {{ book.author }}
        </li>
        {% endfor %}
    </ul>
    {% endblock %}
    

    템플릿 – books/templates/books/book_detail.html

    {% extends "books/base.html" %}
    {% load static %}
    
    {% block title %}{{ book.title }}{% endblock %}
    
    {% block content %}
    <h2>{{ book.title }}</h2>
    <p>저자: {{ book.author }}</p>
    
    <form method="post" action="{% url 'books:vote' book.id %}">
        {% csrf_token %}
        <button type="submit">이 책에 투표하기</button>
    </form>
    
    {% if error_message %}
    <p style="color:red;"><strong>{{ error_message }}</strong></p>
    {% endif %}
    {% endblock %}
    

    템플릿 – books/templates/books/book_results.html

    {% extends "books/base.html" %}
    
    {% block title %}투표 결과{% endblock %}
    
    {% block content %}
    <h2>{{ book.title }}</h2>
    <p>저자: {{ book.author }}</p>
    <p><strong>총 투표 수: {{ book.votes }}</strong></p>
    <a href="{% url 'books:book_list' %}">← 목록으로 돌아가기</a>
    {% endblock %}
    

    CSS – books/static/books/css/style.css

    body {
        font-family: 'Arial', sans-serif;
        background-color: #f2f2f2;
        margin: 2rem;
    }
    
    .container {
        background: white;
        border-radius: 10px;
        padding: 2rem;
        box-shadow: 0 0 10px rgba(0,0,0,0.1);
    }
    
    h1 {
        color: #4a4a4a;
    }
    
    .book-list {
        list-style-type: none;
        padding: 0;
    }
    
    .book-list li {
        padding: 8px 0;
        border-bottom: 1px solid #ddd;
    }
    

    설정 – settings.py STATIC 설정 확인

    STATIC_URL = "static/"
    
    python manage.py makemigrations
    python manage.py migrate
    python manage.py runserver
    
    TOP
    preload preload